package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageBean;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.dto.QueryDeviceDataDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliyunIotProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.vo.DeviceDataGraphVo;
import com.zzyl.vo.DevicePropertyStatusVo;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;

@Service
@Slf4j
public class DeviceServiceImpl implements DeviceService {

    @Autowired
    Client client;
    @Autowired
    AliyunIotProperties aliyunIotProperties;
    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    DeviceMapper deviceMapper;

    @Override
    @SneakyThrows
    public void syncProductList() {
        QueryProductListRequest request = new QueryProductListRequest();
        request.setCurrentPage(1);
        request.setPageSize(200);
        request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        //发送请求
        QueryProductListResponse response = client.queryProductList(request);
        //将结果拷贝到list集合中，并转换为json格式
        List<ProductVo> productVos = BeanUtil.copyToList(response.body.data.list.productInfo, ProductVo.class);
        //存储到redis中
        stringRedisTemplate.opsForValue().set(CacheConstants.IOT_ALL_PRODUCT, JSON.toJSONString(productVos));

    }

    @Override
    public List<ProductVo> selectallProduct() {
        String list = stringRedisTemplate.opsForValue().get(CacheConstants.IOT_ALL_PRODUCT);
        if (StrUtil.isBlank(list)) {
            return List.of();
        }
        List<ProductVo> list1 = JSON.parseArray(list, ProductVo.class);
        return list1;
    }

    @Override
    @SneakyThrows
    public void RegisterDevice(DeviceDto dto) {
        log.info("==========================================================={}",dto);
        String Iotid = null;
        //添加设备到阿里云平台上面
        try {
            //创建请求
            RegisterDeviceRequest request = dto.getRegisterDeviceRequest();
            //设置实例id
            request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());

            RegisterDeviceResponse response = client.registerDevice(request);
            if (!response.body.success) {
                throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
            }
            if (StrUtil.isBlank(response.body.data.iotId)) {
                throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
            }
            Iotid = response.body.data.iotId;
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        //将设备数据添加到数据库中
        try {
            Device device = BeanUtil.toBean(dto, Device.class);
            device.setIotId(Iotid);
            if (device.getLocationType()==0){
                device.setPhysicalLocationType(-1);
            }
            deviceMapper.insert(device);
        } catch (Exception e) {
            //如果添加到数据库中失败，就会删除之前在阿里云平台上的设备
            DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
            deleteDeviceRequest.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
            deleteDeviceRequest.setIotId(Iotid);
            client.deleteDevice(deleteDeviceRequest);
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_DATA_ERROR);
        }
    }

    @Override
    public PageBean<DeviceVo> query(DevicePageQueryDto dto) {
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        Page<DeviceVo> deviceVos = deviceMapper.selectPage(dto);
        return PageBean.of(deviceVos, DeviceVo.class);
    }

    @Override
    @SneakyThrows
    public DeviceVo queryDeviceDetail(QueryDeviceDetailRequest deviceDetailRequest) {
        deviceDetailRequest.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        QueryDeviceDetailResponse response = client.queryDeviceDetail(deviceDetailRequest);

        DeviceVo vo = deviceMapper.selectByIotId(deviceDetailRequest.getIotId());
        BeanUtil.copyProperties(response.body.data, vo);
        return vo;
    }

    @Override
    @SneakyThrows
    public DevicePropertyStatusVo queryDevicePropertyStatus(QueryDevicePropertyStatusRequest request) {
        request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        QueryDevicePropertyStatusResponse response = client.queryDevicePropertyStatus(request);
        DevicePropertyStatusVo vo = BeanUtil.toBean(response.body.data, DevicePropertyStatusVo.class);
        vo.list.getPropertyStatusInfo().sort((o1, o2) -> o1.getIdentifier().equalsIgnoreCase("HeartRate") ? -1 : 1);
        return vo;
    }

    @Override
    @Transactional
    @SneakyThrows
    public void updatedevice(DeviceDto dto) {
        Device device = BeanUtil.toBean(dto, Device.class);
        deviceMapper.updateByPrimaryKey(device);
        Device device1 = deviceMapper.selectByPrimaryKey(dto.getId());
        String iotId = device1.getIotId();

        try {
            BatchUpdateDeviceNicknameRequest request = new BatchUpdateDeviceNicknameRequest();
            request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
            BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo batchUpdateDeviceNicknameRequest = new BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo();
            batchUpdateDeviceNicknameRequest.setIotId(iotId);
            batchUpdateDeviceNicknameRequest.setDeviceName(dto.getDeviceName());
            batchUpdateDeviceNicknameRequest.setProductKey(dto.getProductKey());
            batchUpdateDeviceNicknameRequest.setNickname(dto.getNickname());
            request.setDeviceNicknameInfo(List.of(batchUpdateDeviceNicknameRequest));
            BatchUpdateDeviceNicknameResponse Response = client.batchUpdateDeviceNickname(request);
            if (!Boolean.TRUE.equals(Response.body.success)) {
                throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }
    }

    @Override
    @SneakyThrows
    @Transactional
    public void delete(DeviceDto dto) {
        deviceMapper.deleteByIotId(dto.getIotId());

        try {
            DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
            deleteDeviceRequest.setIotId(dto.getIotId());
            deleteDeviceRequest.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
            DeleteDeviceResponse Response = client.deleteDevice(deleteDeviceRequest);
            if (!Response.body.success) {
                throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }

    }

    @Override
    public List<DeviceDataGraphVo> day(QueryDeviceDataDto dto) {
        List<DeviceDataGraphVo> day = deviceMapper.day(dto);
        DeviceDataGraphVo deviceDataGVo = new DeviceDataGraphVo();
        List<DeviceDataGraphVo> vos = deviceDataGVo.dayInstance(LocalDateTimeUtil.of(dto.getStartTime()));
        vos.forEach(deviceDataGraphVo -> {
            day.forEach(deviceDataGVo1 -> {
                if (deviceDataGVo1.getDateTime().compareTo(deviceDataGraphVo.getDateTime())==0){
                    deviceDataGraphVo.setDataValue(deviceDataGVo1.getDataValue());
                }
            });
        });
        return vos;
    }

    @Override
    public List<DeviceDataGraphVo> week(QueryDeviceDataDto dto) {
        List<DeviceDataGraphVo> week = deviceMapper.week(dto);
        log.info("================================================{}",week);

        DeviceDataGraphVo deviceDataGVo = new DeviceDataGraphVo();
        List<DeviceDataGraphVo> vos = deviceDataGVo.weekInstance(LocalDateTimeUtil.of(dto.getStartTime()));
        log.info("================================================{}",vos);
        vos.forEach(deviceDataGraphVo -> {
            week.forEach(deviceDataGVo1 -> {
                if (deviceDataGVo1.getDateTime().compareTo(deviceDataGraphVo.getDateTime())==0){
                    deviceDataGraphVo.setDataValue(deviceDataGVo1.getDataValue());
                }
            });
        });

        return vos;
    }

    @Override
    @SneakyThrows
    public QueryThingModelPublishedResponseBody.QueryThingModelPublishedResponseBodyData selectid(DeviceDto dto) {
        QueryThingModelPublishedRequest request = new QueryThingModelPublishedRequest();
        request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        request.setProductKey(dto.getProductKey());
        QueryThingModelPublishedResponse response = client.queryThingModelPublished(request);
        log.info("========================================================={}",JSON.toJSONString(response.body.data));
        return response.body.data;
    }
}
